/*!
 * template.js v0.7.1 (https://github.com/yanhaijing/template.js)
 * API https://github.com/yanhaijing/template.js/blob/master/doc/api.md
 * Copyright 2015 yanhaijing. All Rights Reserved
 * Licensed under MIT (https://github.com/yanhaijing/template.js/blob/master/MIT-LICENSE.txt)
 */
/* eslint-disable */
;(function(root, factory) {
  var template = factory(root);
  if (typeof define === 'function' && define.amd) {
      // AMD
      define('template', function() {
          return template;
      });
  } else if (typeof exports === 'object') {
      // Node.js
      module.exports = template;
  } else {
      // Browser globals
      var _template = root.template;

      template.noConflict = function() {
          if (root.template === template) {
              root.template = _template;
          }

          return template;
      };
      root.template = template;
  }
}(this, function(root) {
  'use strict';
  var o = {
      sTag: '<%',//开始标签
      eTag: '%>',//结束标签
      compress: false,//是否压缩html
      escape: true, //默认输出是否进行HTML转义
      error: function (e) {}//错误回调
  };
  var functionMap = {}; //内部函数对象
  //修饰器前缀
  var modifierMap = {
      '': function (param) {return nothing(param)},
      'h': function (param) {return encodeHTML(param)},
      'u': function (param) {return encodeURI(param)}
  };

  var toString = {}.toString;
  var slice = [].slice;
  function type(x) {
      if(x === null){
          return 'null';
      }

      var t= typeof x;

      if(t !== 'object'){
          return t;
      }

      var c = toString.call(x).slice(8, -1).toLowerCase();
      if(c !== 'object'){
          return c;
      }

      if(x.constructor==Object){
          return c;
      }

      return 'unknown';
  }

  function isObject(obj) {
      return type(obj) === 'object';
  }
  function isFunction(fn) {
      return type(fn) === 'function';
  }
  function isString(str) {
      return type(str) === 'string';
  }
  function extend() {
      var target = arguments[0] || {};
      var arrs = slice.call(arguments, 1);
      var len = arrs.length;
   
      for (var i = 0; i < len; i++) {
          var arr = arrs[i];
          for (var name in arr) {
              target[name] = arr[name];
          }
   
      }
      return target;
  }
  function clone() {
      var args = slice.call(arguments);
      return extend.apply(null, [{}].concat(args));
  }
  function nothing(param) {
      return param;
  }
  function encodeHTML(source) {
      return String(source)
          .replace(/&/g,'&amp;')
          .replace(/</g,'&lt;')
          .replace(/>/g,'&gt;')
          .replace(/\\/g,'&#92;')
          .replace(/"/g,'&quot;')
          .replace(/'/g,'&#39;');
  }
  function compress(html) {
      return html.replace(/\s+/g, ' ').replace(/<!--[\w\W]*?-->/g, '');
  }
  function consoleAdapter(cmd, msg) {
      typeof console !== 'undefined' && console[cmd] && console[cmd](msg);
  }
  function handelError(e) {
      var message = 'template.js error\n\n';

      for (var key in e) {
          message += '<' + key + '>\n' + e[key] + '\n\n';
      }
      message += '<message>\n' + e.message + '\n\n';
      consoleAdapter('error', message);

      o.error(e);
      function error() {
          return 'template.js error';
      }
      error.toString = function () {
          return '__code__ = "template.js error"';
      }
      return error;
  }
  function parse(tpl, opt) {
      var code = '';
      var sTag = opt.sTag;
      var eTag = opt.eTag;
      var escape = opt.escape;
      function parsehtml(line) {
          // 单双引号转义，换行符替换为空格
          line = line.replace(/('|")/g, '\\$1');
          var lineList = line.split('\n');
          var code = '';
          for (var i = 0; i < lineList.length; i++) {
              code += ';__code__ += ("' + lineList[i] + (i === lineList.length - 1 ? '")\n' : '\\n")\n');
          }
          return code;
      }
      function parsejs(line) {              
          //var reg = /^(:?)(.*?)=(.*)$/;
          var reg = /^(?:=|(:.*?)=)(.*)$/
          var html;
          var arr;
          var modifier;

          // = := :*=
          // :h=123 [':h=123', 'h', '123']
          if (arr = reg.exec(line)) {
              html = arr[2]; // 输出
              if (Boolean(arr[1])) {
                  // :开头
                  modifier = arr[1].slice(1);
              } else {
                  // = 开头
                  modifier = escape ? 'h' : '';
              }

              return ';__code__ += __modifierMap__["' + modifier + '"](typeof (' + html + ') !== "undefined" ? (' + html + ') : "")\n';
          }
          
          //原生js
          return ';' + line + '\n';
      }

      var tokens = tpl.split(sTag);

      for (var i = 0, len = tokens.length; i < len; i++) {
          var token = tokens[i].split(eTag);

          if (token.length === 1) {
              code += parsehtml(token[0]);
          } else {
              code += parsejs(token[0], true);
              if (token[1]) {
                  code += parsehtml(token[1]);
              }
          }
      }
      return code;
  }
  function compiler(tpl, opt) {
      var mainCode = parse(tpl, opt);

      var headerCode = '\n' + 
      '    var html = (function (__data__, __modifierMap__) {\n' + 
      '        var __str__ = "", __code__ = "";\n' + 
      '        for(var key in __data__) {\n' + 
      '            __str__+=("var " + key + "=__data__[\'" + key + "\'];");\n' + 
      '        }\n' + 
      '        eval(__str__);\n\n';

      var footerCode = '\n' + 
      '        ;return __code__;\n' + 
      '    }(__data__, __modifierMap__));\n' + 
      '    return html;\n';

      var code = headerCode + mainCode + footerCode;
      code = code.replace(/[\r]/g, ' '); // ie 7 8 会报错，不知道为什么
      try {
          var Render = new Function('__data__', '__modifierMap__', code); 
          Render.toString = function () {
              return mainCode;
          }
          return Render;
      } catch(e) {
          e.temp = 'function anonymous(__data__, __modifierMap__) {' + code + '}';
          throw e;
      }  
  }
  function compile(tpl, opt) {
      opt = clone(o, opt);

      try {
          var Render = compiler(tpl, opt);
      } catch(e) {
          e.name = 'CompileError';
          e.tpl = tpl;
          e.render = e.temp;
          delete e.temp;
          return handelError(e);
      }

      function render(data) {
          data = clone(functionMap, data);
          try {
              var html = Render(data, modifierMap);
              html = opt.compress ? compress(html) : html;
              return html;
          } catch(e) {
              e.name = 'RenderError';
              e.tpl = tpl;
              e.render = Render.toString();
              return handelError(e)();
          }            
      }

      render.toString = function () {
          return Render.toString();
      };
      return render;
  }
  function template(tpl, data) {
      if (typeof tpl !== 'string') {
          return '';
      }

      var fn = compile(tpl);
      if (!isObject(data)) {
          return fn;
      }

      return fn(data);
  }

  template.config = function (option) {
      if (isObject(option)) {
          o = extend(o, option);
      }
      return clone(o);
  };

  template.registerFunction = function(name, fn) {
      if (!isString(name)) {
          return clone(functionMap);
      }
      if (!isFunction(fn)) {
          return functionMap[name];
      }

      return functionMap[name] = fn;
  }
  template.unregisterFunction = function (name) {
      if (!isString(name)) {
          return false;
      }
      delete functionMap[name];
      return true;
  }

  template.registerModifier = function(name, fn) {
      if (!isString(name)) {
          return clone(modifierMap);
      }
      if (!isFunction(fn)) {
          return modifierMap[name];
      }

      return modifierMap[name] = fn;
  }
  template.unregisterModifier = function (name) {
      if (!isString(name)) {
          return false;
      }
      delete modifierMap[name];
      return true;
  }

  template.__encodeHTML = encodeHTML;
  template.__compress = compress;
  template.__handelError = handelError;
  template.__compile = compile;
  template.version = '0.7.1';
  return template;
}));